/**
 * Sarue
 * @author Felipe Pupo Rodrigues
 * @constructor BSD
 * @description Framework para controlar javascripts dinamicos usando classe, namespace e addons
 */

/*
 * @class Sarue
 * @description Contem todas classes e métodos necessário na inicialização do Sarue
 */
Sarue = {
    propertys: {
        /*
        * @member Sarue
        * @method [public] construct
        * @description Ainda não implementado, ideia é fazer tipo de um seletor mágico parecido com jquery
        */
        construct: function () {

        }
    },
    abstracts: {
        /*
        * @member Sarue
        * @property [static]{object} REFERENCE
        * @description Guarda o elemento SCRIPT em que foi chamado o Sarue
        */
        REFERENCE: null,
        /*
        * @member Sarue
        * @property [static]{string} PATHFW
        * @description Path onde estao os arquivos do Sarue
        */
        PATHFW: '',
        /*
        * @member Sarue
        * @property [static]{string} PATHJS
        * @description Path onde estao todos os javascripts
        */
        PATHJS: '',
        /*
        * @member Sarue
        * @property [static]{array} ADDONS
        * @description Array dos Addons pré carregados
        */
        ADDONS: [],

        /*
        * @member Sarue
        * @method [static] initialize
        * @description Dispara ações iniciais do Sarue, carrega o controle master
        */
        initialize: function () {
            this._events();
            this._addons();

            this.Class.require('Controller.Master', this._runatController);
        },

        /*
        * @member Sarue
        * @method [static] _runatController
        * @description Verifica e carrega o controle atual da página
        */
        _runatController: function () {
            var url = window.location.href;
            var index = (window.location.pathname == '/' || window.location.pathname == '');

            var control = this.Tools.getMetaTag('Controller'), instance;

            if (!control) {
                var name = index ? 'home' : this.Tools.getFileName(url).replace(/\-+/gim, '_');

                if (!name || name == '') {
                    name = this.Tools.getRelativePath(url + '/');
                }

                control = name.replace(name.charAt(0), name.charAt(0).toUpperCase());
            }

            instance = 'Instance.' + control;
            control = 'Controller.' + control;

            this.Class.require(control, function (c) {
                Sarue.Class.namespace(instance, null, c);
            }, function () {
                Sarue.Class.namespace(instance, null, Controller.Master);
                this.parentNode.removeChild(this);
            });
        },

        /*
        * @member Sarue
        * @method [static] _events
        * @description altera eventos de reload e erro da página
        */
        _events: function () {
            var parent = this;

            this.Tools.addHandler(document, 'onkeydown', function () {
                if (window.event && window.event.keyCode == 116) { // Capture and remap F5
                    window.event.keyCode = 505;
                }

                if (window.event && window.event.keyCode == 505) { // New action for F5
                    parent.Tools.pageRefresh();
                    return false;
                }
            });

            this.Tools.onErrorHandler(function (message, fileName, lineNumber) {
                //ignore errors without detail
                if (!message || !fileName || !lineNumber) return false;

                //ignore scripts not found
                if (message.search('loading script') != -1) return false;

                return parent.Error({
                    name: 'Window OnError',
                    message: message,
                    fileName: fileName,
                    lineNumber: lineNumber
                });
            });
        },

        /*
        * @member Sarue
        * @method [static] _addons
        * @description Carrega a lista de Addons do preloader
        */
        _addons: function () {
            if (this.ADDONS) {
                for (var c = 0; c < this.ADDONS.length; c++) {
                    var scope = this.ADDONS[c];

                    if (scope.search(/\./) == -1) {
                        scope += '.' + scope;
                    };

                    this.Class.require('Addons.' + scope, null, null, false, true);
                }
            }
        },

        /*
        * @member Sarue
        * @class Error
        * @description Trata os erros da página
        */
        Error: {
            propertys: {
                /*
                * @member Sarue.Error
                * @method [public] construct
                * @param {string} file
                * @param {array} handlers
                * @description Adiciona o handler em um escopo de arquivo
                */
                construct: function (file, handlers) {
                    if (handlers)
                        for (var x = 0; x < handlers.length; x++)
                            this.self.addHandler(handlers[x][0], handlers[x][1], handlers[x][2] || file);
                }
            },
            abstracts: {
                TYPES: {},
                IGNORE: [],

                /*
                * @member Sarue.Error
                * @method [static] construct
                * @description Adiciona erros comuns
                */
                construct: function () {
                    this('undefined', [
                        ['CLASS_INSTANCE_ERROR', '{message}'],
						['CLASS_NOT_DEFINED', '{class} was not defined in {file}.'],
						['METHOD_IS_CAMELCASE', '{property} was not CamelCase in {file}.'],
						['PROPERTY_IS_UPPERCASE', '{property} was not UpperCase in {file}.'],
						['PARAMS_NOT_DEFINED', '{params} is not defined in {function}.'],
						['FILE_NOT_FOUND', '{file} was not found.']
					]);
                },

                /*
                * @member Sarue.Error
                * @method [static] addHandler
                * @param {string} name
                * @param {string} message
                * @param {string} file ?
                * @description Adiciona um novo tipo de handler
                */
                addHandler: function (name, message, file) {
                    this.TYPES[name] = {
                        name: name,
                        message: message,
                        fileName: file
                    };
                },

                /*
                * @member Sarue.Error
                * @method [static] handler
                * @param {string} type
                * @param {object} params ?
                * @description Dispara um erro
                */
                handler: function (type, params) {
                    try {
                        if (!type) {
                            this.handler('PARAMS_NOT_DEFINED', {
                                'params': ['type', 'params'],
                                'function': 'Sarue.Error.handler',
                                'line': 125
                            });
                        }

                        if (params && !params['stack']) {
                            var e = this.TYPES[type];
                            e.message = e.message && params ? Sarue.Tools.srpl(e.message, params) : 'undefined';
                            e.lineNumber = params ? params.line : 'undefined';
                        } else {
                            var e = params;
                        }

                        if (!e.fileName && !e.lineNumber)
                            return false;

                        if (this.IGNORE)
                            for (var i = 0, ignore; ignore = this.IGNORE[i]; i++) {
                                if (!ignore.lineNumber && ignore.fileName && e.fileName.search(ignore.fileName) != -1)
                                    return true;
                                if (!ignore.fileName && ignore.lineNumber && e.lineNumber == ignore.lineNumber)
                                    return true;
                                if (ignore.fileName && e.fileName.search(ignore.fileName) != -1 && ignore.lineNumber && e.lineNumber == ignore.lineNumber)
                                    return true;
                            }
                        this.display(e);
                    } catch (e) {
                        //this.display(e);
                    }


                    return true;
                },

                /*
                * @member Sarue.Error
                * @method [static] display
                * @param {object} error
                * @description Mostra o erro na página
                */
                display: function (e) {
                    var error = 'Error (' + e.name + ')\n\n';
                    error += 'File: ' + e.fileName + '\n';
                    error += 'Line: ' + e.lineNumber + '\n';
                    error += 'Message: ' + e.message + '\n';

                    alert(error);
                },

                /*
                * @member Sarue.Error
                * @method [static] ignore
                * @param {string} file ?
                * @param {number} line ?
                * @description Ignora arquivo e linha de erro
                */
                ignore: function (file, line, type) {
                    return this.IGNORE.push({
                        type: type,
                        fileName: file,
                        lineNumber: line
                    });
                }
            }
        },

        URI: {
            propertys: {
                ORIGINAL: null,
                SCHEME: null,
                HOST: null,
                PORT: null,
                PATH: null,
                QUERYSTRING: null,
                QUERY: null,
                HASH: null,
                URI: null,
                SEGMENTS: null,
                PATHANDQUERY: null,
                USERINFO: null,

                construct: function (string) {
                    //if (this.self.CACHE[string])
                    //    return this.self.CACHE[string];

                    this.ORIGINAL = string;

                    this.SCHEME = this.getScheme();
                    this.HOST = this.getHost();
                    this.PORT = this.getPort();
                    this.PATH = this.getPath();
                    this.QUERYSTRING = this.getQueryString();
                    this.QUERY = this.getQuery();
                    this.HASH = this.getHash();
                    this.URI = this.getUri();
                    this.USERINFO = this.getUserInfo();
                    this.PATHANDQUERY = (this.PATH || '') + (this.QUERYSTRING ? '?' + this.QUERYSTRING : '');
                    this.SEGMENTS = this.PATH.split('/');

                    this.self.CACHE[string] = this;
                },

                getHash: function () {
                    return this.self.getHash(this.ORIGINAL);
                },
                getQueryString: function () {
                    return this.self.getQueryString(this.ORIGINAL);
                },
                getQuery: function (key) {
                    return this.self.getQuery(this.ORIGINAL, key);
                },
                getScheme: function () {
                    return this.self.getScheme(this.ORIGINAL);
                },
                getHost: function () {
                    return this.self.getHost(this.ORIGINAL);
                },
                getPort: function () {
                    return this.self.getPort(this.ORIGINAL);
                },
                getPath: function () {
                    return this.self.getPath(this.ORIGINAL);
                },
                getUserInfo: function () {
                    return this.self.getUserInfo(this.ORIGINAL);
                },
                getUri: function () {
                    return this.self.getUri(this.ORIGINAL);
                }

            },
            abstracts: {
                CACHE: {},
                REGHASH: /\#(.+)$/,
                REGQUERY: /\?([^#]+)/,
                REGSCHEME: /(^[^\:\/\/]+\:\/\/)/,
                REGHOST: /([^\:\/\/]+\:\/\/)?([^\@]+\@)?([^\/\?\#\:]+)/,
                REGPORT: /([^\:\/\/]+\:\/\/)?([^\@]+\@)?([^\/\?\#\:]+)?\:([0-9]+)/,
                REGUSERINFO: /([^\:\/\/]+\:\/\/)?([^\:]+)\:([^\@]+)\@/,
                REGPATH: /([^\:\/\/]+\:\/\/)?([^\@]+\@)?([^\/\?\#]+)?(\/[^\?\#]+)?/,
                REGURI: /([^\:\/\/]+\:\/\/)?([^\@]+\@)?([^\?\#\:]+)/,

                getHash: function (str) {
                    var hash = str.match(this.REGHASH);
                    return hash && hash[1] ? hash[1] : null;
                },
                getQueryString: function (str) {
                    var query = str.match(this.REGQUERY);
                    return query && query[1] ? query[1] : null;
                },
                getQuery: function (str, key) {
                    var query = this.getQueryString(str) || '';
                    query = query.split('&');

                    var objs = {};

                    for (var c = 0; c < query.length; c++) {
                        var attr = query[c].split('=');
                        objs[attr[0]] = attr[1];
                    }

                    return key ? objs[key] : objs;
                },
                getScheme: function (str) {
                    var scheme = str.match(this.REGSCHEME);
                    return scheme && scheme[1] ? scheme[1] : null;
                },
                getHost: function (str) {
                    var host = str.match(this.REGHOST);
                    return host && host[3] ? host[3] : null;
                },
                getPort: function (str) {
                    var port = str.match(this.REGPORT);
                    return port && port[4] ? port[4] : null;
                },
                getPath: function (str) {
                    var path = str.match(this.REGPATH);
                    return path ? (path[4] ? path[4] : (path[3] ? path[3] : null)) : null;
                },
                getUserInfo: function (str) {
                    var info = str.match(this.REGUSERINFO);
                    return info && info[2] && info[3] ? { username: info[2], password: info[3]} : null;
                },
                getUri: function (str) {
                    var uri = str.match(this.REGURI);
                    return uri && uri[3] ? (uri[1] || '') + uri[3] : null;
                }
            }
        },

        /*
        * @membrer Sarue
        * @class Tools
        * @description Funcões gerais
        */
        Tools: {
            abstracts: {
				UIDS: {},
				
				uid: function(ns){
					this.UIDS[(ns = ns || 'General')] = this.UIDS[ns] || {};
					
					var id = new Date().getTime();
					
					if(this.UIDS[ns][id] >= 0){
						id = id + '-' + (++this.UIDS[ns][id]);
					}
					else{
						this.UIDS[ns][id] = 0;
						id = id + '-0';
					}
					
					return id; 
				},
                /*
                * @member Sarue.Tools
                * @method [static] getFileName
                * @param {string} url
                * @return {string} file
                * @description Pega o nome do arquivo na url
                */
                getFileName: function (str) {
                    str = str.substring(str.lastIndexOf("/") + 1).split('.'); str.pop();
                    return str.join('/');
                },
                /*
                * @member Sarue.Tools
                * @method [static] getExtension
                * @param {string} url
                * @return {string} extension
                * @description Pega a extenção do arquivo
                */
                getExtension: function (str) {
                    return str.substring(str.lastIndexOf(".") + 1);
                },
                /*
                * @member Sarue.Tools
                * @method [static] getPath
                * @param {string} url
                * @return {string} path
                * @description Pega apenas o path de uma url
                */
                getPath: function (str) {
                    str = str.split('/');
                    while (str.length > 0 && str.pop() == "") { };
                    return str.join('/') + '/';
                },
                /*
                * @member Sarue.Tools
                * @method [static] getVars
                * @param {string} url
                * @return {object} variables
                * @description Pega as variáveis GET
                */
                getVars: function (str) {
                    var vars = str.match(/\?([^#]+)/i);
                    vars = vars && vars[1] ? vars[1] : '';
                    vars = vars.split('&');

                    var objs = {};

                    for (var c = 0; c < vars.length; c++) {
                        var attr = vars[c].split('=');
                        objs[attr[0]] = attr[1];
                    }

                    return objs;
                },
                /*
                * @member Sarue.Tools
                * @method [static] getHash
                * @param {string} url
                * @return {string} hash
                * @description Pega o hash de uma url
                */
                getHash: function (str) {
                    str = str.split('#');
                    return str[1] ? str[1] : '';
                },
                /*
                * @member Sarue.Tools
                * @method [static] getRelativePath
                * @param {string} url
                * @return {string} path
                * @description Pega a ultima path da url
                */
                getRelativePath: function (str) {
                    str = str.split('/');
                    str.pop();
                    return str.pop();
                },
                /*
                * @member Sarue.Tools
                * @method [static] getMetaTag
                * @param {string} name
                * @return {string} value
                * @description Pega o valor de uma metatag
                */
                getMetaTag: function (name) {
                    var metas = document.getElementsByTagName('meta');
                    for (var x = 0; x < metas.length; x++) {
                        if (metas[x] && metas[x].name == name) {
                            return metas[x].content;
                        }
                    }
                },
                /*
                * @member Sarue.Tools
                * @method [static] pageRefresh
                * @description Recarrega a página
                */
                pageRefresh: function () {
                    //document.location = document.location.href;
                    window.location.reload(true);
                },
                /*
                * @member Sarue.Tools
                * @method [static] addHandler
                * @param {object} obj
                * @param {string} evnt
                * @param {function} handler
                * @description Adiciona um evento em um objeto
                */
                addHandler: function (obj, evnt, handler) {
                    if (obj.addEventListener) {
                        obj.addEventListener(evnt.replace(/^on/, ''), handler, false);
                    } else {
                        if (obj[evnt]) {
                            var origHandler = obj[evnt];
                            obj[evnt] = function (evt) {
                                origHandler(evt);
                                handler(evt);
                            }
                        } else {
                            obj[evnt] = function (evt) {
                                handler(evt);
                            }
                        }
                    }
                },
                /*
                * @member Sarue.Tools
                * @method [static] onErrorHandler
                * @param {function} handler
                * @description Adiciona um evento de erro na página
                */
                onErrorHandler: function (evnt) {
                    var oFn;
                    if (typeof window.onerror == 'function') {
                        oFn = window.onerror;
                        window.onerror = function () {
                            oFn.apply(this, arguments);
                            evnt.apply(this, arguments);
                        }
                    } else {
                        window.onerror = evnt;
                    }
                },
                /*
                * @member Sarue.Tools
                * @method [static] patchId
                * @param {string} url
                * @return {string} id
                * @description Converte uma url em um id válido
                */
                patchId: function (str) {
                    try {
                        str = str.match(/\:\/\/[^\/]*\/([^\#\?]*)/);
                        str = str[1];
                        var clean = /[^A-z0-9]/g;
                        return str.replace(clean, "_").toLowerCase();
                    } catch (e) {
                        return '';
                    }
                },
                /*
                * @member Sarue.Tools
                * @method [static] patchId
                * @param {string} string
                * @return {string} clean
                * @description Limpa espaços em branco do comeco e fim de uma string
                */
                trim: function (str) {
                    return str.replace(/^\s+|\s+$/g, "");
                },
                /*
                * @member Sarue.Tools
                * @method [static] patchId
                * @param {string} string
                * @param {object} replace
                * @param {regexp} format ?
                * @return {string} string
                * @description Altera uma string aplicando novo conteudo
                */
                srpl: function (str, data, format) {
                    format = format || /\{([A-z0-9\.]*)\}/gi;

                    return decodeURI(str).replace(format, function (o, a) {
                        var ns = a.split('.');
                        var sc = data;

                        for (var x = 0; x < ns.length; x++) {
                            sc = sc ? sc[ns[x]] : '';
                        }

                        var tp = (typeof sc).toLowerCase();

                        return (tp != 'function') ? sc : sc.apply(sc, [data, a]);
                    });
                },
                /*
                * @member Sarue.Tools
                * @method [static] sfmt
                * @param {string} string
                * @param {string} replace ...
                * @description Altera uma string aplicando novo conteudo, sem especificar chave
                */
                sfmt: function (str) {
                    for (var x = 1, sfmt = []; x < arguments.length; x++)
                        sfmt[x - 1] = arguments[x];

                    return this.srpl(str, sfmt);
                },
                /*
                * @member Sarue.Tools
                * @method [static] sfmt
                * @param {object} object
                * @return {object} object
                * @description Clona um objeto e todo seu conteudo
                */
                clone: function (obj) {
                    if (obj == null || typeof obj != "object") return obj;
                    if (obj.constructor != Object && obj.constructor != Array) return obj;
                    if (obj.constructor == Date || obj.constructor == RegExp || obj.constructor == Function ||
				        obj.constructor == String || obj.constructor == Number || obj.constructor == Boolean)
                        return new obj.constructor(obj);

                    var to = new obj.constructor(),
						clone = Sarue._bios ? Sarue.abstracts.Tools.abstracts.clone : Sarue.Tools.clone;

                    for (var name in obj) {
                        to[name] = clone(obj[name], null);
                    }

                    return to;
                },
                each: function (obj, fn) {
                    var returning = null;

                    switch (this.type(obj)) {
                        case "array":
                        case "collection":
                            returning = [];
                            for (var i = 0; i < obj.length; i++)
                                returning[i] = fn.apply(obj[i], [i]);
                            break;
                        case "object":
                            returning = {};
                            for (var i in obj)
                                returning[i] = fn.apply(obj[i], [i]);
                            break;
                    }

                    return returning;
                },
                type: function (item) {
                    if (item == null) return 'null';

                    if (item.nodeName) {
                        if (item.nodeType == 1) return 'element';
                        if (item.nodeType == 3) return (/\S/).test(item.nodeValue) ? 'textnode' : 'whitespace';
                    } else if (typeof item.length == 'number') {
                        if (item.callee) return 'arguments';
                        if (!item.split && ('item' in item)) return 'collection';
                        if (Object.prototype.toString.apply(item) === '[object Array]') return 'array';
                    }

                    return (typeof item).toLowerCase();
                },
                istype: function (obj, type) {
                    return type && (this.type(obj) == type.toLowerCase());
                }
            }
        },
        /*
        * @member Sarue
        * @class Loader
        * @description Classe estatica de carregadores
        */
        Loader: {
            abstracts: {
                /*
                * @member Sarue.Loader
                * @method [static] js
                * @param {string} url
                * @param {function} success ?
                * @param {function} error ?
                * @param {boolean} sync ?
                * @return {boolean} status
                * @description Carrega um arquivo javascript e adiciona na página
                */
                js: function (url, callback, error, sync) {
                    callback = callback || function () { };
                    error = error || function () { };

                    var obj = null;
                    obj = document.createElement('script');
                    //obj.id = Sarue.Tools.patchId(url);
                    obj.name = name;
                    obj.type = 'text/javascript';
                    obj.async = !sync;
                    obj.runat = true;

                    try {
                        obj.onload = obj.onreadystatechange = function () {
                            if (this.runat && (!this.readyState || this.readyState === 'complete' || (this.readyState === 'loaded'))) { //&& this.nextSibling != null
                                this.runat = false;
                                callback.apply(obj, []);
                                this.onload = this.onreadystatechange = null;
                            }
                            else
                                if (this.readyState === 'loaded' && this.nextSibling == null) {
                                    error.apply(obj, []);
                                }
                        }

                        obj.onerror = function () {
                            error.apply(obj, []);
                        }

                        obj.src = url;
                        document.getElementsByTagName('head')[0].appendChild(obj); // Adds element

                    }
                    catch (e) {
                        alert('erro ao incluir javascript');
                        return false;
                    }


                    return obj;

                },
                /*
                * @member Sarue.Loader
                * @method [static] css
                * @param {string} url
                * @param {function} success ?
                * @param {function} error ?
                * @return {boolean} status
                * @description Carrega um arquivo css e adiciona na página
                */
                css: function (url, callback, error) {
                    callback = callback || function () { };
                    error = error || function () { };

                    var name = Sarue.Tools.patchId(url);

                    var obj = document.createElement('link');
                    obj.rel = 'stylesheet';
                    obj.id = name;
                    obj.name = name;
                    obj.type = 'text/css';

                    try {

                        obj.onerror = function () {
                            error.apply(obj, []);
                        };

                        obj.href = url;

                        document.getElementsByTagName('head')[0].appendChild(obj);

                        if (callback)
                            callback.apply(obj, []);

                        return true;
                    }
                    catch (e) {
                        alert('erro ao incluir css');
                        return false;
                    }
                }
            }
        },
        /*
        * @member Sarue
        * @class Require
        * @description Carrega arquivos javascript que contem classes
        */
        Require: {
            propertys: {
                LIST: [],
                SYNC: true,

                /*
                * @member Sarue.Require
                * @property [public]{object} options
                * @description Opções particular
                */
                options: {
                    /*
                    * @member Sarue.Require:options
                    * @property [public]{function} finish
                    * @description Função chamada quando a pilha de scripts terminar
                    */
                    finish: function () { },
                    /*
                    * @member Sarue.Require:options
                    * @property [public]{function} complete
                    * @description Função chamada quando cada script é carregado
                    */
                    complete: function () { }
                },

                /*
                * @member Sarue.Require
                * @method [public] construct
                * @param {string} src
                * @param {function} success ?
                * @param {function} error ?
                * @param {boolean} async ?
                * @description Adiciona um script de classe necessário
                */
                construct: function (src, callback, error, async) {
                    var thiz = Sarue._bios ? Sarue.abstracts.Require.propertys : this,
						self = Sarue._bios ? Sarue.abstracts.Require.abstracts : this.self;

                    self.INSTANCES.push(thiz);

                    if (!src && !callback && !error && !asyn)
                        return thiz;

                    if (!async) {
                        self.ALLSYNC = self.ALLSYNC || thiz;
                        self.ALLSYNC.add(src, callback, error);

                        if (self.ALLSYNC.LIST.length == 1)
                            self.ALLSYNC.load();
                    }
                    else {
                        thiz.SYNC = false;
                        thiz.add(src, callback, error);

                        if (thiz.LIST.length == 1)
                            thiz.load();
                    }
                },

                /*
                * @member Sarue.Require
                * @method [public] add
                * @param {string} src
                * @param {function} success ?
                * @param {function} error ?
                * @description Adiciona o script na lista da instancia atual
                */
                add: function (src, callback, error) {
                    var thiz = Sarue._bios ? Sarue.abstracts.Require.propertys : this,
						self = Sarue._bios ? Sarue.abstracts.Require.abstracts : this.self;

                    self.addInList(src, callback, error, thiz.SYNC, thiz.LIST);
                },

                /*
                * @member Sarue.Require
                * @method [public] load
                * @description Carrega a lista da instancia na ordem
                */
                load: function () {
                    var thiz = Sarue._bios ? Sarue.abstracts.Require.propertys : this,
						self = Sarue._bios ? Sarue.abstracts.Require.abstracts : this.self;

                    self.load(thiz);
                }
            },

            abstracts: {
                INSTANCES: [],
                COMPLETED: {},
                ALLSYNC: null,

                /*
                * @member Sarue.Require
                * @property [static]{object} options
                * @description Opções estaticas
                */
                options: {
                    /*
                    * @member Sarue.Require:options
                    * @property [static]{function} finish
                    * @description Função chamada quando a pilha de todas instancias terminar
                    */
                    finish: function () { },
                    /*
                    * @member Sarue.Require:options
                    * @property [static]{function} complete
                    * @description Função chamada quando cada script é carregado
                    */
                    complete: function () { }
                },

                /*
                * @member Sarue.Require
                * @method [static] addInList
                * @param {string} src
                * @param {function} success ?
                * @param {function} error ?
                * @param {boolean} async ?
                * @param {array} list
                * @description Adiciona um script na lista de uma instancia
                */
                addInList: function (src, callback, error, sync, list) {
                    var self = Sarue._bios ? Sarue.abstracts.Require.abstracts : this;

                    if (!self.COMPLETED[src]) {
                        list.push({
                            src: self.getSrc(src),
                            callback: callback || function () { },
                            error: error || function () { },
                            sync: sync
                        });
                    }
                },

                /*
                * @member Sarue.Require
                * @method [static] getSrc
                * @param {string} src
                * @return {string} src
                * @description Pega src do arquivo junto com sua url
                */
                getSrc: function (src) {
                    var path = Sarue.PATHJS || Sarue.abstracts.PATHJS;
                    return (src.search('http') != -1) ? src : path + src;
                },

                /*
                * @member Sarue.Require
                * @method [static] load
                * @param {instance} instance
                * @description Carrega a lista de uma instancia na ordem
                */
                load: function (instance) {
                    var self = Sarue._bios ? Sarue.abstracts.Require.abstracts : this,
						loader = Sarue._bios ? Sarue.abstracts.Loader.abstracts : Sarue.Loader,
						obj = instance.LIST[0];

                    if (obj) {
                        obj.element = loader.js(obj.src, function () {
                            self.COMPLETED[obj.src] = true;

                            //call complete event
                            instance.options.complete.call(instance.options.complete, obj.element, true);

                            //call calback event
                            obj.callback.apply(this, arguments);

                            self.options.complete.call(self.options.complete, obj.element, true);

                            //remove item of list
                            instance.LIST.shift();
                            self.load(instance);
                        }, function () {
                            self.COMPLETED[obj.src] = false;

                            //call complete event
                            instance.options.complete.call(instance.options.complete, obj.element, false);

                            //call calback event
                            obj.error.apply(this, arguments);

                            self.options.complete.call(self.options.complete, obj.element, false);

                            //remove item of list
                            instance.LIST.shift();
                            self.load(instance);

                            return null;
                        }, obj.sync);
                    }
                    else {
                        if (instance.options.finish) {
                            instance.options.finish.call(instance.options.finish, arguments);
                            instance.options.finish = null;
                        }
                        if (self.options.finish) {
                            var allInstanceFinish = true;

                            for (var x = 0; x < self.INSTANCES.length; x++)
                                allInstanceFinish = allInstanceFinish && (self.INSTANCES[x].LIST.length == 0);

                            if (allInstanceFinish) {
                                self.options.finish.call(self.options.finish, arguments);
                                self.options.finish = null;
                            }
                        }
                    }

                }
            }
        }
    },
    /*
    * @member Sarue
    * @property [private]{object} _bios
    * @description Objeto de funções que inicializa o Sarue
    */
    _bios: {
        /*
        * @member Sarue._bios
        * @property [private]{function} run
        * @description Roda as funções necessárias da inicialização do bios
        */
        run: function () {
            this.setup();
            this.convert();
        },
        /*
        * @member Sarue._bios
        * @property [private]{function} setup
        * @description Seta os valores das variaveis necessárias do Sarue
        */
        setup: function () {
            if (!Array.prototype['indexOf']) {
                Array.prototype.indexOf = function (search) {
                    return this.join(',').indexOf(search);
                }
            }

            Sarue.abstracts.REFERENCE = document.getElementById('sarue_control') || document.getElementByTagName('script')[0];

            var LOCATION = window.location.href;

            //var PATH = (/\:\/\//.test(Sarue.abstracts.REFERENCE.src) || !(/^\//.test(Sarue.abstracts.REFERENCE.src))) ? Sarue.abstracts.REFERENCE.src : LOCATION.replace(/(\/)$/, '') + Sarue.abstracts.REFERENCE.src;
            var PATH = (/\:\/\//.test(Sarue.abstracts.REFERENCE.src)) ? Sarue.abstracts.REFERENCE.src : ((/^\//.test(Sarue.abstracts.REFERENCE.src)) ? LOCATION.match(/[^\/]+\/\/[^\/]+/)[0] + Sarue.abstracts.REFERENCE.src : LOCATION.replace(/(\/)$/, '') + Sarue.abstracts.REFERENCE.src);


            Sarue.abstracts.PATHFW = Sarue.abstracts.Tools.abstracts.getPath(PATH);
            Sarue.abstracts.PATHJS = Sarue.abstracts.Tools.abstracts.getPath(Sarue.abstracts.PATHFW);
            Sarue.abstracts.ADDONS = Sarue.abstracts.Tools.abstracts.getHash(PATH).split(';');

            delete Sarue._bios.setup;
        },
        /*
        * @member Sarue._bios
        * @property [private]{function} klass
        * @description Converte o objeto Sarue em uma Classe
        */
        klass: function (obj) {
            var propertys, abstracts;

            if (!obj) return obj;

            if (obj['propertys']) {
                propertys = {};
                for (var key in obj.propertys)
                    propertys[key] = this.klass(obj.propertys[key]);
            }

            if (obj['abstracts']) {
                abstracts = {};
                for (var key in obj.abstracts)
                    abstracts[key] = this.klass(obj.abstracts[key]);
            }

            return (propertys || abstracts) ? new Class(propertys, abstracts) : obj;

        },
        /*
        * @member Sarue._bios
        * @property [private]{function} convert
        * @description Requisita o arquivo necessário para converter o Sarue em Classe
        */
        convert: function () {
            //Convert Sarue Object in sarue class
            var Klass;

            Sarue.abstracts.Require.propertys.construct(Sarue.abstracts.PATHFW + 'class.js', function () {
                Sarue.abstracts.Require.propertys.LIST = [];
                Sarue.abstracts.Require.abstracts.ALLSYNC = null;

                Sarue.abstracts.Class = Class;

                Klass = Sarue._bios.klass(Sarue);
                delete Sarue;

                window['Sarue'] = Klass;
                window['Sarue'].initialize();
            });

            delete Sarue._bios.convert;
        }
    }
};

Sarue._bios.run();